﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;

using SpiritAlight.Input;

namespace SpiritAlight.Character
{
    abstract class Spirit : ICharecter
    {

        /// <summary>
        /// プレイヤーテクスチャー
        /// </summary>
        Texture2D[,] texture = new Texture2D[4, 3];

        /// <summary>
        /// 移動目標地点
        /// </summary>
        Vector2 targetPoint = new Vector2(0.0f);

        /// <summary>
        /// 移動ベクトル
        /// </summary>
        Vector2 moveVector = Vector2.Zero;


        #region プロパティ

        public Vector2 Position
        {
            get { return position; }
            set { position = value; }
        }
        Vector2 position;
        
        public Direction Direction
        {
            get { return direction; }
        }
        Direction direction;

        public CharacterState State
        {
            get { return state; }
        }
        CharacterState state = CharacterState.Wait;

        public bool IsMoving
        {
            get { return isMoving; }
        }
        bool isMoving = false;

        /// <summary>
        /// 選択中フラグ。
        /// </summary>
        public bool IsSelect
        {
            get;
            set;
        }

        //精霊の画像サイズ。
        virtual public Vector2 Size { get { return textureSize; } }
        protected Vector2 textureSize;
        //精霊の中心座標
        virtual public Vector2 Center { get { return textureSize / 2; } }

        #endregion


        #region メソッド

        
        /// <summary>
        /// キャラクターの初期化
        /// </summary>
        public void Initialize()
        {
            IsSelect = false;
        }

        /// <summary>
        /// リソース読み込み。
        /// </summary>
        /// <param name="Content">コンテンツマネージャ</param>
        public void LoadContent(ContentManager Content)
        {
            
        }

        /// <summary>
        /// プレイヤーの更新処理。
        /// </summary>
        /// <param name="inputState">現在の入力デバイスの状態。</param>
        public void Update(InputState inputState)
        {
            if (inputState[MouseButton.Left] == DeviceState.Pressed)
            {
                if (IntersectPoint(inputState.MousePosition))
                {
                    IsSelect = true;
                }
                else
                {
                    if (IsSelect)
                    {
                        IsSelect = false;
                        MoveStart(inputState.MousePosition);
                    }
                }
            }

            Move();
            ChangeDirection();

        }

        /// <summary>
        /// キャラクターの描画処理。
        /// </summary>
        /// <param name="spriteBatch">描画するSpriteBatch</param>
        /// <param name="sceneColor">シーンの色。</param>
        public void Draw(SpriteBatch spriteBatch, Color sceneColor)
        {

            //キャラクターを表示する。
            try
            {
                spriteBatch.Draw(texture[(Int32)direction, (Int32)state], position, sceneColor);
            }
            catch (Exception) { }
        }

        /// <summary>
        /// 1点とプレイヤー位置が重なっているかどうか調べる。
        /// </summary>
        /// <param name="inPoint">調べる1点の座標。</param>
        /// <returns>重なっている=true</returns>
        public bool IntersectPoint(Vector2 inPoint)
        {
            if (position.X > inPoint.X || position.X + Size.Y < inPoint.X ||
                position.Y > inPoint.Y || position.Y + Size.Y < inPoint.Y)
                return false;

            return true;
        }

        /// <summary>
        /// 移動を開始する。
        /// </summary>
        /// <param name="targetPoint">目標地点。</param>
        public void MoveStart(Vector2 targetPoint)
        {
            isMoving = true;
            this.targetPoint = targetPoint;
        }

        /// <summary>
        /// 移動フラグが経っている際にプレイヤーを移動させる。
        /// </summary>
        public void Move()
        {
            if (isMoving)
            {
                CalcVector();

                position += moveVector;
            }
            if (IsApproximation(Center, targetPoint, new Vector2(10.0f, 10.0f)))
                isMoving = false;
        }

        /// <summary>
        /// 2つの座標がある一定の誤差の範囲内かどうか調べる。
        /// </summary>
        /// <param name="value1">調べる点1</param>
        /// <param name="value2">調べる点2</param>
        /// <param name="tolerance">許される誤差。</param>
        /// <returns>範囲内=true</returns>
        private bool IsApproximation(Vector2 value1, Vector2 value2, Vector2 tolerance)
        {
            if ((value1.X - value2.X <= tolerance.X && value1.X - value2.X >= -tolerance.X) &&
                (value1.Y - value2.Y <= tolerance.Y && value1.Y - value2.Y >= -tolerance.Y))
                return true;

            return false;
        }

        /// <summary>
        /// キャラクターの地点から目標地点へのベクトルを計算する。
        /// </summary>
        private void CalcVector()
        {
            double angle = Math.Atan2((double)targetPoint.X - (double)Center.X,
                                      (double)targetPoint.Y - (double)Center.Y);

            moveVector.X = (float)Math.Sin(angle);
            moveVector.Y = (float)Math.Cos(angle);
        }

        /// <summary>
        /// キャラクターの方向を移動ベクトルに応じて変更する。
        /// </summary>
        private void ChangeDirection()
        {
            if (Math.Abs(moveVector.X) >= Math.Abs(moveVector.Y))
            {
                if (moveVector.X < 0.0f)
                    direction = Direction.Left;
                else
                    direction = Direction.Right;
            }
            else
            {
                if (moveVector.Y < 0.0f)
                    direction = Direction.Up;
                else
                    direction = Direction.Down;
            }
        }
    }
    #endregion
}
